# -*- coding: utf-8 -*-
from .topo_server import TopoServer
from .path_generator import PathGenerator
import threading
import time

'''
控制器维护拓扑并计算路径模块
'''


class Server():
    def __init__(self, server_port=6699, accept_time=1):
        self.server_port = server_port
        self.pg = PathGenerator()
        self.ts = TopoServer(self.server_port)
        self.update = False  # 拓扑十分已经更新
        self.lock = threading.Lock()  # 加锁，防止拓扑在更新时执行最短路
        self.accept_time = accept_time
        self.connect_times = {}  # 连接计数器，k为两端点 v为连通次数的列表，采用列表是因为使用无向图，uv可互换，因此借助列表实现类似指针的功能

    def check_edge_add(self, u, v):
        '''
        惰性更新策略下检查是否需要添加
        '''
        if self.pg.check_edge(u, v):  # 如果边已经存在则无需添加
            return False
        k = u+' '+v
        if k not in self.connect_times:
            self.connect_times[k] = [0]  # 借助列表实现类似指针的功能，两个键都可修改访问这个列表
            self.connect_times[v+' '+u] = self.connect_times[k]
        self.connect_times[k][0] += 1  # 修改列表值
        # print('%s:%s'%(k,self.connect_times[k][0]))
        if self.connect_times[k][0] >= self.accept_time:
            return True
        else:
            return False

    def check_edge_delete(self, u, v):
        '''
        惰性更新策略下检测是否需要删除边
        '''
        # 先重置计数器
        k = u+' '+v
        if k in self.connect_times:
            self.connect_times[k][0] = 0
        if self.pg.check_edge(u, v):  # 如果边已经存在则需删除
            return True
        else:
            return False

    def topo_update_loop(self):
        '''
        拓扑更新
        '''
        # rl = self.ts.recv_loop() # 不用yield 改用多线程形式
        threading.Thread(target=self.ts.recv_loop).start()
        # 可以添加一些惰性更新策略，以应对emane的概率性通断，如连通三次才认为是通的，尽量选择稳定链路
        while True:
            # link = next(rl)
            link = self.ts.link_msg_queue.get()
            # print("get msg %s"%link)
            self.lock.acquire()
            if link[2] == '1':
                if self.check_edge_add(link[0], link[1]) and self.pg.add_edge(link[0], link[1]):
                    # print("添加路径:%s-%s"%(link[0],link[1]))
                    self.update = True
            elif link[2] == '0':
                if self.check_edge_delete(link[0], link[1]) and self.pg.remove_edge(link[0], link[1]):
                    # print("删除路径:%s-%s"%(link[0],link[1]))
                    self.update = True
            self.lock.release()

    def path_update(self):
        '''
        路径更新
        '''
        self.lock.acquire()
        paths = None
        if self.update:
            try:
                paths = self.pg.generate_all_shortest_path()
            except:
                pass
        self.update = False
        self.lock.release()
        return paths

    def get_host_IP(self, ad_hoc_IP):
        '''
        传入其ad_hoc网络IP, 返回其连接控制器的IP
        '''
        return self.ts.IP_map.get(ad_hoc_IP, None)

    def get_mac(self, ad_hoc_IP):
        '''
        传入其ad_hoc网络IP, 返回其mac地址
        '''
        return self.ts.switch_mac.get(ad_hoc_IP, None)

    def get_ad_hoc_IP(self, connect_IP):
        '''
        传入返回其连接控制器的IP, 返回其ad_hoc网络Ip
        '''
        return self.ts.IP_map_R.get(connect_IP, None)

<<<<<<< HEAD
    def remove_ovs(self, ad_hoc_IP):
        '''
        当交换机断开时，在拓扑中删除这个节点
        :param ad_hoc_IP: 这个交换机ad_hoc_IP
        '''
        return self.pg.remove_node(ad_hoc_IP)
=======
    def remove_ovs(self, ovs_connect_IP):
        '''
        当交换机断开时，在拓扑中删除这个节点
        :param ovs_connect_IP: 这个交换机连接控制器所使用的IP
        '''
        return self.pg.remove_node(self.get_ad_hoc_IP(ovs_connect_IP))
>>>>>>> 65743b7ca29b9b630727da9c3f4b2bef9b5344a3

    def reset(self):
        '''
        链路完全故障时清空全部数据
        '''
        time.sleep(3)  # 等待三秒，全部数据处理完
        self.lock.acquire()
        self.pg.clean_topo()
        self.update = False
        self.ts.IP_map.clear()
        self.ts.IP_map_R.clear()
        self.ts.link_msg_queue.clear()
        self.ts.switch_addr.clear()
        self.ts.switch_mac.clear()
        self.connect_times.clear()
        self.lock.release()
